﻿using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Newtonsoft.Json;

namespace ProjectN.Core
{
    [JsonObject(MemberSerialization.OptIn)]
    public class Sequence<T> : IEnumerable<T>, IEnumerable<IdPair<T>> where T : notnull
    {
        [JsonProperty("Values")]
        private readonly Dictionary<int, T> elements = [];

        private readonly Dictionary<int, LinkedListNode<int>> order_mapping = [];

        [JsonProperty("Order")]
        private readonly LinkedList<int> order = [];

        [JsonProperty("NextIdentity")]
        private int nextId = 1;

        public Sequence() { }

        public int Count => elements.Count;

        public bool IsReadOnly => false;

        public int Add(T item)
        {
            var id = nextId++;
            elements[id] = item;
            order_mapping.Add(id, order.AddLast(id));
            return id;
        }

        public void Clear()
        {
            elements.Clear();
            order.Clear();
            nextId = 1;
        }

        public bool Contains(int id)
        {
            return elements.ContainsKey(id);
        }

        public T Get(int id)
        {
            if (!elements.TryGetValue(id, out var item))
                throw new KeyNotFoundException($"ID {id} 不存在");
            return item;
        }

        public void Update(int id, T value)
        {
            if (!this.Contains(id))
                throw new KeyNotFoundException($"ID {id} 不存在");
            elements[id] = value;
        }

        public T this[int id]
        {
            get => Get(id);
            set => Update(id, value);
        }

        public bool Remove(int id)
        {
            if (!elements.TryGetValue(id, out var element))
                return false;
            elements.Remove(id);
            order.Remove(id);
            return true;
        }

        public IEnumerator<T> GetEnumerator()
        {
            return order.Select(id => elements[id]).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        IEnumerator<IdPair<T>> IEnumerable<IdPair<T>>.GetEnumerator()
        {
            return order.Select(id => new IdPair<T>(id, elements[id])).GetEnumerator();
        }

        public void SetFirst(int id)
        {
            if (!elements.ContainsKey(id))
                throw new KeyNotFoundException($"No item with ID {id} found.");
            if (!order_mapping.ContainsKey(id))
                order_mapping[id] = order.Find(id);
            order.Remove(order_mapping[id]);
            order_mapping[id] = order.AddFirst(id);
        }

        public void SetLast(int id)
        {
            if (!elements.ContainsKey(id))
                throw new KeyNotFoundException($"No item with ID {id} found.");
            if (!order_mapping.ContainsKey(id))
                order_mapping[id] = order.Find(id);
            order.Remove(order_mapping[id]);
            order_mapping[id] = order.AddLast(id);
        }
    }
}
